package cc.mrbird.febs.accounting.service.impl;

import cc.mrbird.febs.accounting.dto.detailCost.DetailTotalDTO;
import cc.mrbird.febs.accounting.entity.CompanyProject;
import cc.mrbird.febs.accounting.entity.DetailCost;
import cc.mrbird.febs.accounting.entity.Project;
import cc.mrbird.febs.accounting.dto.detailCost.Salary;
import cc.mrbird.febs.accounting.entity.StandardSub;
import cc.mrbird.febs.accounting.mapper.DetailCostMapper;
import cc.mrbird.febs.accounting.service.IProjectService;
import cc.mrbird.febs.accounting.service.ISalaryService;
import cc.mrbird.febs.accounting.service.IStandardSubService;
import cc.mrbird.febs.common.utils.FebsUtil;
import cc.mrbird.febs.utils.CodeConstant;
import cc.mrbird.febs.utils.CodeUtils;
import cc.mrbird.febs.utils.PermissionUtil;
import cc.mrbird.febs.utils.YearMonthMapUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SalaryServiceImpl implements ISalaryService {

    @Resource
    private IStandardSubService standardSubService;
    @Resource
    private DetailCostMapper detailCostMapper;
    @Resource
    private IProjectService projectService;
    @Resource
    private CompanyProjectServiceImpl companyProjectService;

    @Override
    public File getSalaryWord(String year, String month, String projectId) throws Exception {
        // 修改成自己的数据封装
        String[] projectIds = projectId.split(",");
        Map<String, Object> dataMap = new HashMap<String, Object>();
        dataMap.put("number", projectIds.length);
        dataMap.put("month", month);
        dataMap.put("year", year);
        List<Salary> salaries = new ArrayList<Salary>();
        List<String> yearMonths = new ArrayList<>();
        month = Integer.parseInt(month) < 10 ? "0" + month : month;
        yearMonths.add(year + "-" + month);
        List<StandardSub> standardSubs = standardSubService.queryByType(3);
        ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
        LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Project::getIsDeleted, 0);
        List<Project> projects = projectService.getBaseMapper().selectList(queryWrapper);
        Map<Long, String> projectNameMap = projects.stream().collect(Collectors.toMap(Project::getId, Project::getProjectName));

        LambdaQueryWrapper<CompanyProject> q = new LambdaQueryWrapper<>();
        q.in(CompanyProject::getProjectId, Arrays.asList(projectIds));
        List<CompanyProject> companyProjects = companyProjectService.getBaseMapper().selectList(q);

        for (String id : projectIds) {
            // todo
            // 获取项目对应公司ids
            List<Long> companyIds = new ArrayList<>();
            for (CompanyProject companyProject : companyProjects) {
                if (companyProject.getProjectId().toString().equals(id)) {
                    companyIds.add(companyProject.getCompanyId());
                }
            }

            Map<String, Double> codeValueMap = new HashMap<>();
            String yearMonth = year + "-" + month ;
            for (Long companyId : companyIds) {
                List<DetailCost> detailCosts = detailCostMapper.queryDetailCodeByProjectIdAndYear(companyId, Long.parseLong(id), yearMonths);
                // 把公司id加入key ??有必要？直接加？
                detailCosts.forEach(e -> {
                    String dKey = companyId + "==" + e.getDetailSubjectCode() + "==" + e.getYearMonth();
                    codeValueMap.put(dKey, e.getCost().doubleValue());
                });
                for (StandardSub standardSub : standardSubs) {
                    String code = standardSub.getCode();
                    String rule = standardSub.getCalculateRule();
                    Set<String> ruleCodeSet = CodeUtils.getRuleCodeSet(rule);
                    Double reuslt = 0d;
                    // 判断类别，为 4 ,5 类直接累加计算, 否则通过存入公式计算
                    switch (code) {
                        case CodeConstant.thirdPartCode:
                            for (DetailCost e : detailCosts) {
                                if (e.getYearMonth().equals(yearMonth) && e.getType() == 4) {
                                    reuslt += Double.parseDouble(e.getCost().toString());
                                }
                            }
                            break;
                        case CodeConstant.selfIncomeCode:
                            for (DetailCost e : detailCosts) {
                                if (e.getYearMonth().equals(yearMonth) && e.getType() == 5) {
                                    reuslt += Double.parseDouble(e.getCost().toString());
                                }
                            }
                            break;
                        case CodeConstant.thirdCostSumCode: {
                            String key = CodeConstant.pendingPaymentCode;
                            for (DetailCost e : detailCosts) {
                                if (e.getYearMonth().equals(yearMonth) && (e.getType() == 6 || e.getDetailSubjectCode().equals(key))) {
                                    reuslt += Double.parseDouble(e.getCost().toString());
                                }
                            }
                            break;
                        }
                        case CodeConstant.projectIncomeCode: {
                            // 加上自有收入合计和第三方收入合计
                            String key = companyId + "==" + CodeConstant.selfIncomeCode + "==" + yearMonth;
                            reuslt += codeValueMap.get(key);
                            key = companyId + "==" + CodeConstant.thirdPartCode + "==" + yearMonth;
                            reuslt += codeValueMap.get(key);
                            break;
                        }
                        default:
                            // 通过公式计算
                            String standardSubKey = companyId + "==" + standardSub.getCode() + "==" + year + "-" + month;
                            if (codeValueMap.containsKey(standardSubKey)) {
                                continue;
                            }
                            String realRule = rule;
                            for (String ruleCode : ruleCodeSet) {
                                String key = companyId + "==" + ruleCode + "==" + year + "-" + month;
                                Double value = codeValueMap.get(key);
                                if (Objects.isNull(value)) {
                                    value = 0d;
                                }
                                realRule = realRule.replaceAll("【" + ruleCode + "】", value.toString());
                            }
                            //计算公式
                            try {
                                reuslt = (Double) jse.eval(realRule);
                            } catch (ScriptException e) {
                                e.printStackTrace();
                            }
                            if (reuslt.isNaN() || reuslt.isInfinite()) {
                                reuslt = 0d;
                            }
                            break;
                    }
                    reuslt = Double.parseDouble(String.format("%.2f",reuslt));
                    codeValueMap.put(companyId + "==" + code + "==" + year + "-" + month, reuslt);
                }

                // 计算营业利润
                List<DetailTotalDTO> standardSubExtras = YearMonthMapUtils.getStandardSubs(3).stream().
                        filter(e -> e.getType() <= 3 ).collect(Collectors.toList());
                for (DetailTotalDTO detailTotalDTO : standardSubExtras) {
                    String rule = detailTotalDTO.getCalculateStr();
                    Set<String> ruleCodeSet = CodeUtils.getRuleCodeSet(detailTotalDTO.getCalculateStr());
                    String realRule = rule;
                    for (String ruleCode : ruleCodeSet) {
                        String key = companyId + "==" + ruleCode + "==" + year + "-" + month;
                        Double value = codeValueMap.get(key);
                        if (Objects.isNull(value)) {
                            value = 0d;
                        }
                        realRule = realRule.replaceAll("【" + ruleCode + "】", Double.toString(value));
                    }
                    //计算公式
                    Double reuslt = 0d;
                    try {
                        reuslt = (Double) jse.eval(realRule);
                    } catch (ScriptException e) {
                        e.printStackTrace();
                    }
                        reuslt = Double.parseDouble(String.format("%.2f", reuslt));
                    codeValueMap.put(companyId + "==" + detailTotalDTO.getName(), reuslt);
                }
            }

            Double people = 0d;
            Double budget = 0d;
            Double should = 0d;
            Double actual = 0d;
            double profit = 0d;

            for (Long companyId : companyIds) {
                people += codeValueMap.getOrDefault(companyId + "==" + CodeConstant.monthPeople + "==" + yearMonth, 0d);
                budget += codeValueMap.getOrDefault(companyId + "==" + CodeConstant.selfIncomeCode + "==" + yearMonth, 0d);
                should += codeValueMap.getOrDefault(companyId + "==" + CodeConstant.shouldPay + "==" + yearMonth, 0d);
                actual += codeValueMap.getOrDefault(companyId + "==" + CodeConstant.actualPay + "==" + yearMonth, 0d);
                profit += codeValueMap.getOrDefault(companyId + "==" + "营业利润", 0d);
            }


            Salary salary = new Salary();
            salary.setName(projectNameMap.get(Long.parseLong(id)));
            salary.setBudget(String.format("%.2f", budget));
            salary.setPeople(people.intValue() + "");
            salary.setShould(String.format("%.2f", should));
            salary.setActual(String.format("%.2f", actual));
            String profitStr = profit >= 0d ? "毛利" + String.format("%.2f", profit) : "亏损" + String.format("%.2f", profit * (-1));
            boolean ifLoss = !(profit >= 0d);
            salary.setIfLoss(ifLoss);
            salary.setProfit(profitStr);
            salaries.add(salary);
        }
        dataMap.put("salaries",salaries);

        // 生成FTL模板文档
        Configuration configuration = new Configuration();
        configuration.setDefaultEncoding("UTF-8");
        configuration.setClassForTemplateLoading(this.getClass(), "/templates/wordTemplate");

        // 生成Word文档
        Template t = configuration.getTemplate("monthlySalary.ftl", "UTF-8");  // 获取模板
        File outFile = new File("name");
        Writer w = new OutputStreamWriter(Files.newOutputStream(outFile.toPath()), StandardCharsets.UTF_8);
        t.process(dataMap, w);
        w.close();
        return outFile;
    }

}
